export class LcsDiff {
  #src;

  #dst;

  #m;

  #n;

  /**
   * @type {FinalizationRegistry<number[][]>}
   */
  #f = new FinalizationRegistry(() => {
    LcsDiff.#dp = [];
  });

  /**
   * @type {number[][]}
   */
  static get dp() {
    return LcsDiff.#dp;
  }

  /**
   * @type {number[][]}
   */
  static #dp;

  /**
   * @param {string} src
   * @param {string} dst
   */
  constructor(src, dst) {
    this.#src = src;
    this.#dst = dst;
    this.#m = src.length;
    this.#n = dst.length;
    LcsDiff.#dp = Array.from({ length: this.#m + 1 }, () =>
      Array.from({ length: this.#n + 1 }).fill(0),
    );
    this.#f.register(this, LcsDiff.#dp);
  }

  /**
   * @returns {number}
   */
  exploit() {
    // computed
    for (let i = 0; i <= this.#m; i++) {
      for (let j = 0; j <= this.#n; j++) {
        if (i === 0) {
          LcsDiff.dp[i][j] = j;
        } else if (j === 0) {
          LcsDiff.dp[i][j] = i;
          // 计算标准的莱文斯坦距离（允许插入、删除、替换）的动态规划方程
        } else if (this.#src[i - 1] === this.#dst[j - 1]) {
          LcsDiff.dp[i][j] = LcsDiff.dp[i - 1][j - 1];
        } else {
          LcsDiff.dp[i][j] =
            1 + Math.min(LcsDiff.dp[i - 1][j], LcsDiff.dp[i][j - 1]);
        }
      }
    }
    return LcsDiff.dp[this.#m][this.#n];
  }
}

if (import.meta.main) {
  const res = new LcsDiff("abc", "acb");
  res.exploit();
  logMat(LcsDiff.dp);
}
/**
 * @param {unknown[][]} mat
 */
function logMat(mat) {
  console.assert(
    mat.length ? mat[0].length === mat.length : true,
    "mat has not square shape",
  );
  console.log(mat.map((row) => row.join(" ")).join("\n"));
}

// if (global.gc) {
//   global.gc();
// }
